#pragma once

#include <ctime>
#include <set>
#include <string>
#include <unordered_set>
#include <vector>

class ParkingSpotManager {
public:
    ParkingSpotManager(const ParkingSpotManager &) = delete;
    static ParkingSpotManager *getInstance() {
        static ParkingSpotManager instance;
        return &instance;
    }

    // Function to get a random available ID
    std::string getID() {
        if (availableSpots.empty()) {
            return ""; // No available spots
        }

        // Get a random index from available spots
        int randomIndex = std::rand() % availableSpots.size();
        std::string selectedID = availableSpots[randomIndex];

        // Mark the selected ID as used
        availableSpots.erase(availableSpots.begin() + randomIndex);
        usedSpots.insert(selectedID);

        return selectedID;
    }

    // Function to release an ID back to availability
    bool releaseID(const std::string &id) {
        if (usedSpots.find(id) != usedSpots.end()) {
            usedSpots.erase(id);
            availableSpots.push_back(id);
            return true;
        }
        return false; // ID was not in use
    }

private:
    std::vector<std::string> availableSpots;
    std::unordered_set<std::string> usedSpots;

    ParkingSpotManager() {
        initializeSpots();
        std::srand(std::time(0)); // Seed for random number generation
    }

    void initializeSpots() {
        const std::vector<std::string> sections = {"A", "B", "C", "D"};
        for (const auto &section : sections) {
            for (int floor = 1; floor <= 3; ++floor) {
                for (int pos = 1; pos <= 10; ++pos) {
                    std::string spotID = section + std::to_string(floor) +
                                         (pos < 10 ? "0" : "") +
                                         std::to_string(pos);
                    availableSpots.push_back(spotID);
                }
            }
        }
    }
};